/**
 ******************************************************************************
 * @file    
 * @author 
 * @Version 
 * @Date    
 * @brief 
 *******************************************************************************  
 **/
#include "zb32l03x_hal.h"
#include "bsp_lcd.h"

const uint8_t lcd_initial_tab[] =
{
        0xe2, // soft reset开始进行软复位
        0xa2, // bias select确定为1/9BIAS 1/65duty
        0xa1, // ADC select确定SEG反扫seg131--->seg0
        0xc8, // SHL select确定COM为正扫com0--->com63
        0x26, // regulator resistor select V0调整电阻设定(1 + Rb/Ra)=6.5
        0x81, // The Electronic Volume (Double Byte Command)数字电位器调节VO输出电压(也就是对比度)两字节
        0x05, //
        0x2d, // power control1 on内部倍压电路开启,需分以下三步打开电路
        0X2e, // power control2
        0x2f, // power control3
        0xf8, // The Booster Ratio (Double Byte Command)设定倍压数,两字节
        0x00, //"00"最大4倍压,"01"最大5倍压,"03"最大6倍压
        0x40, // 设定起始行
        0xa4, // Display All Points ON/OFF to Normal display mode正常显示模式选择
        0xaf  // Display ON/OFF开显示设定
};

/*
*********************************************************************************************************
*	功能说明: 初始化
*	形    参:
*	返 回 值:
* 说    明：
*********************************************************************************************************
*/

void bsp_lcd_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    TIM_HandleTypeDef           TIMx = {0};
    TIM_OC_InitTypeDef          TIMxOC = {0};
    uint8_t i,page,column;

    BSP_LCD_RST_CLKENABLE();
    BSP_LCD_SCLK_CLKENABLE();
    BSP_LCD_CS_CLKENABLE();
    BSP_LCD_SDA_CLKENABLE();
    BSP_LCD_AO_CLKENABLE();
    BSP_LCD_BL_CLKENABLE();
    BSP_LCD_BL_TIMBASE_CLK_ENABLE();

    GPIO_InitStruct.Pin = BSP_LCD_RST_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
    GPIO_InitStruct.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(BSP_LCD_RST_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(BSP_LCD_RST_PORT,BSP_LCD_RST_PIN,GPIO_PIN_SET);
    

    GPIO_InitStruct.Pin = BSP_LCD_SCLK_PIN;
    HAL_GPIO_Init(BSP_LCD_SCLK_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(BSP_LCD_SCLK_PORT,BSP_LCD_SCLK_PIN,GPIO_PIN_SET);
    

    GPIO_InitStruct.Pin = BSP_LCD_CS_PIN;
    HAL_GPIO_Init(BSP_LCD_CS_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(BSP_LCD_CS_PORT,BSP_LCD_CS_PIN,GPIO_PIN_SET);
    

    GPIO_InitStruct.Pin = BSP_LCD_SDA_PIN;
    HAL_GPIO_Init(BSP_LCD_SDA_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(BSP_LCD_SDA_PORT,BSP_LCD_SDA_PIN,GPIO_PIN_SET);
    

    GPIO_InitStruct.Pin = BSP_LCD_AO_PIN;
    HAL_GPIO_Init(BSP_LCD_AO_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(BSP_LCD_AO_PORT,BSP_LCD_AO_PIN,GPIO_PIN_SET);
   

    GPIO_InitStruct.Pin = BSP_LCD_RST_PIN;
    HAL_GPIO_Init(BSP_LCD_RST_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(BSP_LCD_RST_PORT,BSP_LCD_RST_PIN,GPIO_PIN_SET);

    GPIO_InitStruct.Pin = BSP_LCD_BL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF;
    GPIO_InitStruct.Pull            = GPIO_PULLUP;
    GPIO_InitStruct.OpenDrain       = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate        = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength     = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Alternate= BSP_LCD_BL_FUN;
    HAL_GPIO_Init(BSP_LCD_BL_PORT, &GPIO_InitStruct);
    

    TIMx.Instance               = BSP_LCD_BL_TIMBASE;
    TIMx.Init.Period            = 1000;                             // TIM1A_ARR Period
    TIMx.Init.Prescaler         = (uint32_t)(HAL_RCC_GetPCLKFreq() / 1000000) - 1;// TIMx Frequency(CK_CNT) = fCK_PSC/(PSC[15:0]+1) = TIMx_FREQ
    TIMx.Init.ClockDivision     = 0;                               // CKD(Clock division)
    TIMx.Init.CounterMode       = TIM_COUNTERMODE_UP;              // Edge alignment mode ,counter up
    TIMx.Init.RepetitionCounter = 0;                               // TIM1A_RCR
    TIMx.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;   // Enable Auto-reload
    HAL_TIM_PWM_Init(&TIMx);

    TIMxOC.OCMode     = TIM_OCMODE_PWM1;                         // PWM mode1 TIM1A_CCMR1
    TIMxOC.Pulse      = TIMx.Init.Period / 10;                    // This value is used to determine the duty cycle,and the default duty cycle is 50%
    TIMxOC.OCPolarity = TIM_OCPOLARITY_HIGH;                      // Output polarity, OC1 is valid at low level

    HAL_TIM_PWM_ConfigChannel(&TIMx, &TIMxOC, BSP_LCD_BL_CHANNEL); // Configure TIM1A Channel1

    HAL_TIM_PWM_Start(&TIMx, BSP_LCD_BL_CHANNEL); //Open PWM Channel1

    for (i = 0; i < sizeof(lcd_initial_tab); i++)
    {
        bsp_lcd_cmdwrite(lcd_initial_tab[ i ]);
    }

    for (page = 0; page < 9; page++)   //page loop
    {
        bsp_lcd_pageset(page);
        bsp_lcd_columnset(0);
        for (column = 0; column < 132; column++)   //column loop
        {
            bsp_lcd_datawrite(0x00);
        }
    }

}

void bsp_lcd_bl_open(void)
{
    uint32_t mask = 0U;
    mask = (TIM_CCER_CC1E_Msk << BSP_LCD_BL_CHANNEL);
    /* Set or reset the CCxE Bit */
    WRITE_REG_MASK(BSP_LCD_BL_TIMBASE->CCER, mask, (TIM_CCx_ENABLE << BSP_LCD_BL_CHANNEL));
}
 /**
  * @brief  打开蜂鸣器
  * @param  
  * @param  
  * @retval NUll
  */

void bsp_lcd_bl_close(void)
{
   TIM_HandleTypeDef           TIMx = {0};
   TIM_OC_InitTypeDef          TIMxOC = {0};
  
    TIMx.Instance               = BSP_LCD_BL_TIMBASE;
    TIMx.Init.Period            = 1000;                             // TIM1A_ARR Period
    TIMx.Init.Prescaler         = (uint32_t)(HAL_RCC_GetPCLKFreq() / 1000000) - 1;// TIMx Frequency(CK_CNT) = fCK_PSC/(PSC[15:0]+1) = TIMx_FREQ
    TIMx.Init.ClockDivision     = 0;                               // CKD(Clock division)
    TIMx.Init.CounterMode       = TIM_COUNTERMODE_UP;              // Edge alignment mode ,counter up
    TIMx.Init.RepetitionCounter = 0;                               // TIM1A_RCR
    TIMx.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;   // Enable Auto-reload
    HAL_TIM_PWM_Init(&TIMx);

    TIMxOC.OCMode     = TIM_OCMODE_PWM1;                          // PWM mode1 TIM1A_CCMR1
    TIMxOC.Pulse      = 0;                                        // This value is used to determine the duty cycle,and the default duty cycle is 50%
    TIMxOC.OCPolarity = TIM_OCPOLARITY_HIGH;                      // Output polarity, OC1 is valid at low level

    HAL_TIM_PWM_ConfigChannel(&TIMx, &TIMxOC, BSP_LCD_BL_CHANNEL); // Configure TIM1A Channel1

    HAL_TIM_PWM_Stop(&TIMx, BSP_LCD_BL_CHANNEL); //Open PWM Channel1
}
/**
  * @brief  设置频率
  * @param  
  * @param  
  * @retval NUll
  */
 void bsp_lcd_bl_level(uint8_t level)
 {
   TIM_HandleTypeDef           TIMx = {0};
   TIM_OC_InitTypeDef          TIMxOC = {0};
   if(level>=9)
   {
    level=9;
   }
    TIMx.Instance               = BSP_LCD_BL_TIMBASE;
    TIMx.Init.Period            = 1000;                             // TIM1A_ARR Period
    TIMx.Init.Prescaler         = (uint32_t)(HAL_RCC_GetPCLKFreq() / 1000000) - 1;// TIMx Frequency(CK_CNT) = fCK_PSC/(PSC[15:0]+1) = TIMx_FREQ
    TIMx.Init.ClockDivision     = 0;                               // CKD(Clock division)
    TIMx.Init.CounterMode       = TIM_COUNTERMODE_UP;              // Edge alignment mode ,counter up
    TIMx.Init.RepetitionCounter = 0;                               // TIM1A_RCR
    TIMx.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;   // Enable Auto-reload
    HAL_TIM_PWM_Init(&TIMx);

    TIMxOC.OCMode     = TIM_OCMODE_PWM1;                         // PWM mode1 TIM1A_CCMR1
    TIMxOC.Pulse      = 100*level;                    // This value is used to determine the duty cycle,and the default duty cycle is 50%
    TIMxOC.OCPolarity = TIM_OCPOLARITY_HIGH;                      // Output polarity, OC1 is valid at low level

    HAL_TIM_PWM_ConfigChannel(&TIMx, &TIMxOC, BSP_LCD_BL_CHANNEL); // Configure TIM1A Channel1

    HAL_TIM_PWM_Start(&TIMx, BSP_LCD_BL_CHANNEL); //Open PWM Channel1
 }


void bsp_lcd_resetenable(void)
{
  //BSP_LCD_RST=0;
  HAL_GPIO_WritePin(BSP_LCD_RST_PORT,BSP_LCD_RST_PIN,GPIO_PIN_RESET);
}

void bsp_lcd_resetdisable(void)
{
  //BSP_LCD_RST=1;
  HAL_GPIO_WritePin(BSP_LCD_RST_PORT,BSP_LCD_RST_PIN,GPIO_PIN_SET);
}

/**
 * @brief 写指令子程序
 * 
 * @param command 指令
 * */
void bsp_lcd_cmdwrite(uint8_t command)
{
    uint8_t counter;

    

    HAL_GPIO_WritePin(BSP_LCD_CS_PORT,BSP_LCD_CS_PIN,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(BSP_LCD_AO_PORT,BSP_LCD_AO_PIN,GPIO_PIN_RESET);

    for (counter = 0; counter < 8; counter++)
    {
        HAL_GPIO_WritePin(BSP_LCD_SCLK_PORT,BSP_LCD_SCLK_PIN,GPIO_PIN_RESET);
        if(((command & 0x80) == 0x80))
        {
          HAL_GPIO_WritePin(BSP_LCD_SDA_PORT,BSP_LCD_SDA_PIN,GPIO_PIN_SET);
        }
        else
        {
           HAL_GPIO_WritePin(BSP_LCD_SDA_PORT,BSP_LCD_SDA_PIN,GPIO_PIN_RESET); 
        }
        command <<= 1;
        HAL_GPIO_WritePin(BSP_LCD_SCLK_PORT,BSP_LCD_SCLK_PIN,GPIO_PIN_SET);
    }
    HAL_GPIO_WritePin(BSP_LCD_CS_PORT,BSP_LCD_CS_PIN,GPIO_PIN_SET);
}

/**
 * @brief 写数据子程序
 * 
 * @param command 数据
 */
void bsp_lcd_datawrite(uint8_t command)
{

    uint8_t counter;

    HAL_GPIO_WritePin(BSP_LCD_CS_PORT,BSP_LCD_CS_PIN,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(BSP_LCD_AO_PORT,BSP_LCD_AO_PIN,GPIO_PIN_SET);

    for (counter = 0; counter < 8; counter++)
    {
        HAL_GPIO_WritePin(BSP_LCD_SCLK_PORT,BSP_LCD_SCLK_PIN,GPIO_PIN_RESET);
        if(((command & 0x80) == 0x80))
        {
          HAL_GPIO_WritePin(BSP_LCD_SDA_PORT,BSP_LCD_SDA_PIN,GPIO_PIN_SET);
        }
        else
        {
           HAL_GPIO_WritePin(BSP_LCD_SDA_PORT,BSP_LCD_SDA_PIN,GPIO_PIN_RESET); 
        }
        command <<= 1;
        HAL_GPIO_WritePin(BSP_LCD_SCLK_PORT,BSP_LCD_SCLK_PIN,GPIO_PIN_SET);
    }
    HAL_GPIO_WritePin(BSP_LCD_CS_PORT,BSP_LCD_CS_PIN,GPIO_PIN_SET);
}
/**
 * @brief 设置行
 * 
 * @param column 行号
 */
void bsp_lcd_columnset(uint8_t column)
{
    bsp_lcd_cmdwrite(0x10 | (column >> 4));
    bsp_lcd_cmdwrite(0x00 | (column & 0x0f));
}
/**
 * @brief 设置页
 * 
 * @param page 页号
 */
void bsp_lcd_pageset(uint8_t page)
{
    bsp_lcd_cmdwrite(0xb0 + page);
}

/**
 * @brief 设置地址
 * 
 * @param column 行号
 * @param page 页号
 */
void bsp_lcd_addset(uint8_t column, uint8_t page)
{

    bsp_lcd_columnset(column+4);
    bsp_lcd_pageset(page);
}

